﻿// Login form, (c)2010 Knihovnik
// This file is licensed under LGPL license, see more at http://www.gnu.org/licenses/lgpl.html
namespace FacebookChat
{

	#region Usings

	using System;
	using System.Diagnostics;
	using System.Threading;
	using System.Windows.Forms;
	using jabber.client;
	using jabber.connection;
	using System.Security.Cryptography.X509Certificates;
	using System.Net.Security;

	#endregion

	/// <summary>
	/// Login form
	/// </summary>
	public partial class LoginForm : Form
	{

		#region Members
		
		private JabberClient m_client; // Jabber client class
		private System.Windows.Forms.Timer m_timeOut; // Timeout timer

		#endregion

		#region Constructors

		/// <summary>
		/// Constructor
		/// </summary>
		public LoginForm()
		{
			this.InitializeComponent();
			
			// Initialize resource strings
			this.lbPassword.Text = Properties.Resources.Password;
			this.lbSignIn.Text = Properties.Resources.SignIn;
			this.btLogin.Text = Properties.Resources.LogIn;
			this.btQuit.Text = Properties.Resources.Exit;
			this.lbUserName.Text = Properties.Resources.Username;
			this.cxRemember.Text = Properties.Resources.Remember;

			// Initialize timeout timer
			this.m_timeOut = new System.Windows.Forms.Timer();
			this.m_timeOut.Interval = 10000; // TODO: Maybe settings?
			this.m_timeOut.Tick += new EventHandler(this.OnTimeOut);
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets instance of <see cref="JabberClient"/> class
		/// </summary>
		internal JabberClient Client
		{
			get
			{
				return this.m_client;
			}
		}

		#endregion

		#region Override Methods

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			// Set stuff from settings
			this.cxRemember.Checked = Properties.Settings.Default.RememberUserName;
			if (this.cxRemember.Checked)
				this.tbUserName.Text = Properties.Settings.Default.LastUserName;
		}

		protected override void OnShown(EventArgs e)
		{
			base.OnShown(e);
			// When's form shown, focus password text field if username is filled
			if (!string.IsNullOrEmpty(this.tbUserName.Text))
				this.tbPassword.Focus();
		}

		#endregion

		#region Methods

		/// <summary>
		/// Saves username
		/// </summary>
		private void Save()
		{
			Properties.Settings.Default.RememberUserName = this.cxRemember.Checked;
			if (this.cxRemember.Checked)
				Properties.Settings.Default.LastUserName = this.tbUserName.Text;
			Properties.Settings.Default.Save();
		}

		/// <summary>
		/// Disables UI controls
		/// </summary>
		private void DisableControls()
		{
			this.tbPassword.Enabled =
				this.tbUserName.Enabled =
				this.btLogin.Enabled =
				this.cxRemember.Enabled = false;
			Application.DoEvents();
		}

		/// <summary>
		/// Enables UI controls
		/// </summary>
		private void EnableControls()
		{
			this.Invoke(new MethodInvoker(delegate
				{
					this.tbPassword.Enabled =
						this.tbUserName.Enabled =
						this.btLogin.Enabled =
						this.cxRemember.Enabled = true;
				}));
		}

		/// <summary>
		/// Runs login process in own thread
		/// </summary>
		private void Login()
		{
			Thread thread = new Thread(new ThreadStart(delegate
			{
				// Initial settings
				this.m_client = new JabberClient();
				this.m_client.Connection = ConnectionType.Socket;
				this.m_client.AutoStartCompression = false;
				this.m_client.AutoLogin = true;
				this.m_client.Port = 5222;
				this.m_client.Priority = 0;
				this.m_client.PlaintextAuth = true;
				this.m_client.SSL = false;

				this.m_client.Resource = "FDC";
				this.m_client.Server = "chat.facebook.com";
				this.m_client.NetworkHost = "chat.facebook.com";
				this.m_client.User = this.tbUserName.Text;
				this.m_client.Password = this.tbPassword.Text;
				this.m_client.OnInvalidCertificate += new System.Net.Security.RemoteCertificateValidationCallback(delegate(object obj,X509Certificate cert, X509Chain chain, SslPolicyErrors err)
					{
						return true;
					});
				try
				{
					// Reg. events
					this.m_client.OnAuthenticate += new bedrock.ObjectHandler(Client_OnAuthenticate);
					this.m_client.OnAuthError += new jabber.protocol.ProtocolHandler(Client_OnAuthError);
					this.m_client.Connect();
					// Start timeout timer
					this.Invoke(new MethodInvoker(delegate
					{
						this.m_timeOut.Enabled = true;
						this.m_timeOut.Start();
					}));
				}
				catch (Exception ex)
				{
					// Oops.. something went wrong
					this.Invoke(new MethodInvoker(delegate
					{
						Debug.Write(ex);
						MessageBox.Show(Properties.Resources.LoginException,
							Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
						this.EnableControls();
					}));
				}
			}));

			this.DisableControls();
			thread.Start(); // Let's start the show!
		}

		#endregion

		#region Event Handlers

		private void btLogin_Click(object sender, EventArgs e)
		{
			this.Login();
		}

		private void btQuit_Click(object sender, EventArgs e)
		{
			this.Save();
			Application.Exit();
		}

		void Client_OnAuthError(object sender, System.Xml.XmlElement rp)
		{
			// Auth. error
			this.Invoke(new MethodInvoker(delegate
				{
					this.m_timeOut.Stop(); // Stop timeout timer
					// Inform the user that something went wrong
					MessageBox.Show(Properties.Resources.AuthError, 
						Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
					// Enable UI
					this.EnableControls();
					// Standard behavior - select wrong password and focus
					this.tbPassword.SelectAll();
					this.tbPassword.Focus();
				}));
		}

		void  Client_OnAuthenticate(object sender)
		{
			// Auth. success
			this.Invoke(new MethodInvoker(delegate { this.m_timeOut.Stop(); })); // Stop timeout timer
			// Unregister events
			this.m_client.OnAuthenticate -= new bedrock.ObjectHandler(Client_OnAuthenticate);
			this.m_client.OnAuthError -= new jabber.protocol.ProtocolHandler(Client_OnAuthError);
			this.Save(); // Save username if neccessary
			this.EnableControls(); // Enable UI
			this.DialogResult = DialogResult.OK; // Set dialog result to OK
		}

		private void OnTimeOut(object sender, EventArgs e)
		{
			this.m_client.Close();  // Stop connection process
			this.m_timeOut.Stop(); // Stop timer
			this.EnableControls(); // Enable UI controls

			// Inform the user
			this.Invoke(new MethodInvoker(delegate
			{
				MessageBox.Show(string.Format(Properties.Resources.TimeOut, Environment.NewLine),
					Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Warning);
			}));
		}

		private void TextField_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				e.SuppressKeyPress = true;
				e.Handled = true;
				this.Login();
			}
		}

		#endregion

	}
}
